#include "system_tick.h"
#include "led_sw.h"
#include "beep.h"
#include "rf_receive.h"
#include "main.h"

//======================================================
#ifdef _12F629
    __CONFIG(FOSC_INTRCIO & WDTE_OFF & PWRTE_OFF & MCLRE_ON & BOREN_OFF & CP_ON & CPD_ON);
#endif
#ifdef _12F683
//#warning <<<<<<<<<<<<<<  Nho config lockbit lai >>>>>>>>>>>>>>>>
    __CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_OFF & MCLRE_ON & BOREN_OFF & CP_ON & CPD_ON);
#endif


//======================================================
eMainState      s_MainState;
eNormalState    s_NormlState;
eLearningState  s_LearningState;
eBellState      s_BellState;
eAlarmState     s_AlarmState;

#define SetNormalMode( normalState )        quit = true; s_MainState = NORMAL; s_NormlState = normalState
#define SetLearningMode( learningState )    quit = true; s_MainState = LEARNING; s_LearningState = learningState
#define SetBellMode( bellState )            quit = true; s_MainState = BELL; s_BellState = bellState
#define SetAlarmMode( alarmState )          quit = true; s_MainState = ALARM; s_AlarmState = alarmState


void Cleanup(void)
{
    Beep_TurnOff();
    v_SsActive = false;
    OFF_LED;
    SystemtickFlag = false;
}

void BlockingDelay(U8 period)
{
    bool quit = false;
    while(false == quit)
    {
        if (true == SystemtickFlag)
        {
            SystemtickFlag = false;
            if (0 == --period)
            {
                quit = true;
            }
        }
    }
}

void Beep_1_time(void)
{
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
}

void Beep_2_time(void)
{
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
    BlockingDelay(WAITING_FOR_OFF_BEEP);
    
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
}

void Beep_3_time(void)
{
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
    BlockingDelay(WAITING_FOR_OFF_BEEP);
    
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
    BlockingDelay(WAITING_FOR_OFF_BEEP);
    
    Beep_OnBeep();
    BlockingDelay(BEEP_SHORT_PERIOD);
    Beep_TurnOff();
}

void NormalMode(void)
{
    bool quit = false;
#ifdef SLEEP_MODE_ENABLE
    #if (WAIT_FOR_SLEEP_TIMER < 256)
    U8 sleepCounter = 0;
    #else
    U16 sleepCounter = 0;
    #endif
#endif
    
    while( quit == false )
    {
        switch (s_NormlState)
        {
        default:
        case NORMAL_INITRESET:
            {
                ON_LED;
                Beep_1_time();
                BlockingDelay(WAITING_FOR_OFF_LED);
                OFF_LED;
                Cleanup();
                s_NormlState = NORMAL_WAITING_FOR_EVENT;
            } break;
            
        case NORMAL_PREPARE_FOR_WAITING:
            {
                Beep_2_time();
                Cleanup();
                s_NormlState = NORMAL_WAITING_FOR_EVENT;
            } break;
            
        case NORMAL_WAITING_FOR_EVENT:
            {
                if( true == RF_receive() )
                {
                    RF_GetReceiveCode();
                    if( true == RF_IsExist() )
                    {
                        if( LOCK_CODE == s_BitCode )
                        {
                            SetAlarmMode(ALARM_INIT);
                        }
                        else if( UNLOCK_CODE == s_BitCode )
                        {
                            s_NormlState = NORMAL_PREPARE_FOR_WAITING;
                        }
                        else if( BELL_CODE == s_BitCode )
                        {
                            SetBellMode(BELL_INIT);
                        }
                    }
                }
                if( true == SystemtickFlag )
                {
                    SystemtickFlag = false;

                    LedSW_UpdateStatus();
                    if( SW_ACTIVE == SwEvent && SW_ACTIVE == SwStatus)
                    {
                        ON_LED;
                        SetLearningMode(LEARNING_INIT);
                    }
                    #ifdef SLEEP_MODE_ENABLE
                    if( WAIT_FOR_SLEEP_TIMER <= sleepCounter++ )
                    {
                        sleepCounter = 0;
                        Cleanup();wefq
                        SLEEP();
                    }
                    #endif
                }
            } break;
        }
    }
}

void LearningMode(void)
{
    bool quit = false;
    #if (SW_ERASE_TIMER < 256)
        U8 eraseTimer = 0;
    #else
        U16 eraseTimer = 0;
    #endif
    
    #if (SW_LEARNING_TIMEOUT < 256)
        U8 learningTimeout = 0;
    #else
        U16 learningTimeout = 0;
    #endif
    
    #if (TOGGLE_LED_TIMER < 256)
        U8 toggleTimer = 0;
    #else
        U16 toggleTimer = 0;
    #endif
    
    while( quit == false )
    {
        switch (s_LearningState)
        {
        default:
        case LEARNING_INIT:
            {
                ON_LED;
                Beep_OnBeep();
                BlockingDelay(BEEP_LONG_PERIOD);
                learningTimeout = 0;
                toggleTimer = 0;
                eraseTimer = 0;
                Cleanup();
                s_LearningState = LEARNING_WAITING_FOR_EVENT;
            } break;
            
        case LEARNING_WAITING_FOR_EVENT:
            {
                if( true == RF_receive() )
                {
                    RF_GetReceiveCode();
                    if( ( 5 > s_pRFCodeCnt )       &&
                        ( false == RF_IsExist() )  &&
                        ( LOCK_CODE == s_BitCode || UNLOCK_CODE == s_BitCode || BELL_CODE == s_BitCode ) )
                    {
                        s_pRFCode[s_pRFCodeCnt][0] = s_pRFIncome[0];
                        s_pRFCode[s_pRFCodeCnt][1] = s_pRFIncome[1];
                        s_pRFCode[s_pRFCodeCnt][2] = s_pRFIncome[2];
                        s_pRFCodeCnt++;
                        RF_SaveAllRFCode();
                        Beep_1_time();
                    }
                    else
                    {
                        Beep_3_time();
                    }
                    Cleanup();
                    learningTimeout = 0;
                    eraseTimer = 0;
                }
                if( true == SystemtickFlag )
                {
                    SystemtickFlag = 0;

                    LedSW_UpdateStatus();
                    if( SW_LEARNING_TIMEOUT <= learningTimeout++ )
                    {
                        s_LearningState = LEARNING_QUIT;
                    }
                    if(SW_ACTIVE == SwStatus)
                    {
                        ON_LED;
                        if( SW_ERASE_TIMER <= eraseTimer++ )
                        {
                            s_LearningState = LEARNING_ERASE;
                        }
                    }
                    else
                    {
                        eraseTimer = 0;
                        if( TOGGLE_LED_TIMER <= toggleTimer++ )
                        {
                            toggleTimer = 0;
                            INV_LED;
                        }
                    }
                }
            } break;
        
        case LEARNING_ERASE:
            {
                RF_EraseAllRFCode();
                Beep_OnBellBing();
                BlockingDelay(BELL_BING_PERIOD);
                Beep_OnBellBong();
                BlockingDelay(BELL_BONG_PERIOD);
                Beep_TurnOff();
                BlockingDelay(WAITING_FOR_OFF_BEEP);
                Cleanup();
                s_LearningState = LEARNING_INIT;
            } break;

        case LEARNING_QUIT:
            {
                Cleanup();
                SetNormalMode(NORMAL_PREPARE_FOR_WAITING);
            } break;
        }
    }
}

void BellMode(void)
{
    bool quit = false;
    eBellProcessState bellProcess;
    U16 timerCount = 0;
    U8  ssUnactiveCounter = 0;
    U8  bellCount = 0;
    
#ifdef SLEEP_MODE_ENABLE
    #if (WAIT_FOR_SLEEP_TIMER < 256)
    U8 sleepCounter = 0;
    #else
    U16 sleepCounter = 0;
    #endif
#endif
    
    bellProcess = BELL_PROCESS_DELAY;
    while( quit == false )
    {
        switch (s_BellState)
        {
        default:
        case BELL_INIT:
            {
                Beep_OnBellBing();
                BlockingDelay(BELL_BING_PERIOD);
                Beep_OnBellBong();
                BlockingDelay(BELL_BONG_PERIOD);
                timerCount = 0;
                bellCount = 0;
                Cleanup();
                s_BellState = BELL_WAITING_FOR_EVENT;
            } break;
            
        case BELL_WAITING_FOR_EVENT:
            {
                if( true == RF_receive() )
                {
                    RF_GetReceiveCode();
                    if( true == RF_IsExist() )
                    {
                        if( UNLOCK_CODE == s_BitCode )
                        {
                            s_BellState = BELL_QUIT;
                        }
                        else if( BELL_CODE == s_BitCode )
                        {
                            s_BellState = BELL_INIT;
                            bellProcess = BELL_PROCESS_DELAY;
                        }
                        else if( LOCK_CODE == s_BitCode )
                        {
                            Cleanup();
                            SetAlarmMode(ALARM_INIT);
                        }
                    }
                }
                if( true == SystemtickFlag )
                {
                    SystemtickFlag = false;

                    if( true == v_SsActive )
                    {
                        v_SsActive = false;
                        if ( (BELL_PROCESS_IDLE == bellProcess) && (SS_UNACTIVE_COUNTER_MAX <= ssUnactiveCounter) )
                        {
                            bellProcess = BELL_PROCESS_BING;
                            bellCount = 0;
                            timerCount = 0;
                        }
                        ssUnactiveCounter = 0;
                    }
                    else
                    {
                        if (SS_UNACTIVE_COUNTER_MAX > ssUnactiveCounter) ++ssUnactiveCounter;
                    }
                    
                    switch (bellProcess)
                    {
                    default:
                    case BELL_PROCESS_IDLE:
                        {
                            #ifdef SLEEP_MODE_ENABLE
                            if( WAIT_FOR_SLEEP_TIMER <= sleepCounter++ )
                            {
                                sleepCounter = 0;
                                Cleanup();
                                SLEEP();
                            }
                            #endif
                        } break;
                        
                    case BELL_PROCESS_DELAY:
                        {
                            ON_LED;
                            if( BELL_DELAY_FOR_PREPARE <= timerCount++ )
                            {
                                ssUnactiveCounter = 0;
                                Cleanup();
                                bellProcess = BELL_PROCESS_IDLE;
                                OFF_LED;
                            }
                        } break;
                        
                    case BELL_PROCESS_BING:
                        {
                            ON_LED;
                            Beep_OnBellBing();
                            timerCount = 0;
                            bellProcess = BELL_PROCESS_WAITING_FOR_BING;
                        }
                    case BELL_PROCESS_WAITING_FOR_BING:
                        {
                            if( BELL_BING_PERIOD <= timerCount++ )
                            {
                                bellProcess = BELL_PROCESS_BONG;
                            }
                        } break;
                        
                    case BELL_PROCESS_BONG:
                        {
                            OFF_LED;
                            Beep_OnBellBong();
                            timerCount = 0;
                            bellProcess = BELL_PROCESS_WAITING_FOR_BONG;
                        }
                    case BELL_PROCESS_WAITING_FOR_BONG:
                        {
                            if( BELL_BONG_PERIOD <= timerCount++ )
                            {
                                bellProcess = BELL_PROCESS_CHECK_COMPLETE;
                                Beep_TurnOff();
                                timerCount = 0;
                                ++bellCount;
                            }
                        } break;
                        
                    case BELL_PROCESS_CHECK_COMPLETE:
                        {
                            if(BELL_COUNT_MAX == bellCount)
                            {
                                bellProcess = BELL_PROCESS_DELAY;
                            }
                            else
                            {
                                if( BELL_DELAY_PERIOD <= timerCount++ )
                                {
                                    bellProcess = BELL_PROCESS_BING;
                                }
                            }
                        } break;
                    }
                }
            } break;

        case BELL_QUIT:
            {
                Cleanup();
                SetNormalMode(NORMAL_PREPARE_FOR_WAITING);
            } break;
        }
    }
}

void AlarmMode(void)
{
    bool quit = false;
    eAlarmProcessState alarmProcess;
    U16 timerCount = 0;
    U8  toggleLedCnt = 0;
    
#ifdef SLEEP_MODE_ENABLE
    #if (WAIT_FOR_SLEEP_TIMER < 256)
    U8 sleepCounter = 0;
    #else
    U16 sleepCounter = 0;
    #endif
#endif
    
    alarmProcess = ALARM_PROCESS_DELAY;
    while( quit == false )
    {
        switch (s_AlarmState)
        {
        default:
        case ALARM_INIT:
            {
                Beep_1_time();
                timerCount = 0;
                Cleanup();
                s_AlarmState = ALARM_WAITING_FOR_EVENT;
            } break;
            
        case ALARM_WAITING_FOR_EVENT:
            {
                if( true == RF_receive() )
                {
                    RF_GetReceiveCode();
                    if( true == RF_IsExist() )
                    {
                        if( UNLOCK_CODE == s_BitCode )
                        {
                            s_AlarmState = ALARM_QUIT;
                        }
                        else if( ALARM_PROCESS_IDLE == alarmProcess )
                        {
                            if( LOCK_CODE == s_BitCode )
                            {
                                s_AlarmState = ALARM_INIT;
                                alarmProcess = ALARM_PROCESS_DELAY;
                                break;
                            }
                            else if( BELL_CODE == s_BitCode )
                            {
                                SetBellMode(BELL_INIT);
                                break;
                            }
                        }
                    }
                }
                if( true == SystemtickFlag )
                {
                    SystemtickFlag = false;
                    if( true == v_SsActive )
                    {
                        v_SsActive = false;
                        if (ALARM_PROCESS_IDLE == alarmProcess)
                        {
                            alarmProcess = ALARM_PROCESS_ALARM_ON;
                        }
                    }
                    
                    switch (alarmProcess)
                    {
                    default:
                    case ALARM_PROCESS_IDLE:
                        {
                            #ifdef SLEEP_MODE_ENABLE
                            if( WAIT_FOR_SLEEP_TIMER <= sleepCounter++ )
                            {
                                sleepCounter = 0;
                                Cleanup();
                                SLEEP();
                            }
                            #endif
                        } break;
                        
                    case ALARM_PROCESS_DELAY:
                        {
                            ON_LED;
                            if( WAIT_FOR_ALARM_LED <= timerCount++ )
                            {
                                OFF_LED;
                                alarmProcess = ALARM_PROCESS_IDLE;
                            }
                        } break;
                        
                    case ALARM_PROCESS_ALARM_ON:
                        {
                            Beep_OnAlarm();
                            timerCount = 0;
                            toggleLedCnt = 0;
                            alarmProcess = ALARM_PROCESS_WAIT_ALARM_ON;
                        }
                    case ALARM_PROCESS_WAIT_ALARM_ON:
                        {
                            if (ALARM_ON_PERIOD <= timerCount++)
                            {
                                alarmProcess = ALARM_PROCESS_ALARM_OFF;
                            }
                            else
                            {
                                if (ALARM_LED_TOGGLE_TIMER <= toggleLedCnt++)
                                {
                                    toggleLedCnt = 0;
                                    INV_LED;
                                }
                            }
                        } break;
                        
                    case ALARM_PROCESS_ALARM_OFF:
                        {
                            Beep_TurnOff();
                            timerCount = 0;
                            ON_LED;
                            alarmProcess = ALARM_PROCESS_WAIT_ALARM_OFF;
                        }
                    case ALARM_PROCESS_WAIT_ALARM_OFF:
                        {
                            if (ALARM_OFF_PERIOD <= timerCount++)
                            {
                                timerCount = 0;
                                OFF_LED;
                                Cleanup();
                                alarmProcess = ALARM_PROCESS_IDLE;
                            }
                        } break;
                    }
                }
            } break;

        case ALARM_QUIT:
            {
                Cleanup();
                SetNormalMode(NORMAL_PREPARE_FOR_WAITING);
            } break;
        }
    }
}

void main(void) 
{
    OSCCON = 0x75;

    // turn all pin as tri-state 
    TRISIO = 0xFF;
    nGPPU = 0;
    GPIO = 0;
    PIE1 = 0;

    // disable compare mode
    #ifdef _12F629
        CMCON |= 0b111;
    #endif

    #ifdef _12F683
        CMCON0 |= 0b111;
        ANSEL = 0;
        ADON = 0;
    #endif

    SysTick_InitReset();
    LedSW_InitReset();
    Beep_InitReset();
    RF_InitReset();

    // enable Global interrupt
    PEIE = 1;
    GIE = 1;

    s_MainState = NORMAL;
    s_NormlState = NORMAL_INITRESET;
  
#ifdef TESTING_MODE
    Beep_OnAlarm();
    
    while(1)
    {
        if( true == RF_receive() )
        {
            //RF_ResetReceiveFlag();
            RF_GetReceiveCode();
            INV_LED;
            if( true == RF_IsExist() )
            {
                // if( LOCK_CODE == s_BitCode )
                // {
                    // s_MainState = PREPARE_ALARM;
                // }
                // else if( UNLOCK_CODE == s_BitCode )
                // {
                    // s_MainState = PREPARE_NORMAL;
                // }
                // else if( BELL_CODE == s_BitCode )
                // {
                    // s_MainState = PREPARE_BELL;
                // }
            }
        }

        if( true == SystemtickFlag )
        {
            SystemtickFlag = false;

            // if( 100 <= s_TimerCount++ )
            // {
                // s_TimerCount = 0;
                // //INV_LED;
            // }
        }
    
    }
#else    
    while(1) 
    {
        switch ( s_MainState )
        {
        default:
        case NORMAL:
            {
                NormalMode();
            } break;

        case LEARNING:
            {
                LearningMode();
            } break;

        case BELL:
            {
                BellMode();
            } break;

        case ALARM:
            {
                AlarmMode();
            } break;
        }
    }
#endif
}
